﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace Extension {
  /// <summary>
  /// ini文件操作
  /// </summary>
  public static class IniFile {
    #region 读取INI文件

    /// <summary>
    /// 读取ini文件中给定的区域
    /// </summary>
    /// <param name="sectionName">读取的区域名称。若为null，则 returnBuffer 将会获得所有的区域名称</param>
    /// <param name="key">键的名称。若为null，则returnBuffer将会获得所有指定的sectionName下的所有键名</param>
    /// <param name="defaultValue">指示没有找到指定的key时返回的值</param>
    /// <param name="returnBuffer">key所对应的值</param>
    /// <param name="size"></param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns></returns>
    [DllImport("kernel32")]
    private static extern int GetPrivateProfileString(string sectionName, string key, string defaultValue, byte[] returnBuffer, int size, string filePath);
    /// <summary>
    /// 读取ini文件中给定的区域
    /// </summary>
    /// <param name="sectionName">读取的区域名称。若为null，则 returnBuffer 将会获得所有的区域名称</param>
    /// <param name="key">键的名称。若为null，则returnBuffer将会获得所有指定的sectionName下的所有键名</param>
    /// <param name="defaultValue">指示没有找到指定的key时返回的值</param>
    /// <param name="returnBuffer">key所对应的值</param>
    /// <param name="size"></param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns></returns>
    public static int Read(string sectionName, string key, string defaultValue, byte[] returnBuffer, int size, string filePath) {
      int result = GetPrivateProfileString(sectionName, key, defaultValue, returnBuffer, size, filePath);
      return result;
    }
    /// <summary>
    /// 获取ini文件中给定的键的值
    /// </summary>
    /// <param name="sectionName">读取的区域名称。</param>
    /// <param name="key">读取的键名</param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns>读取到的值</returns>
    public static string GetSpecifiedValue(string sectionName, string key, string filePath) {
      byte[] buffer = new byte[2048];
      int length = GetPrivateProfileString(sectionName, key, "Read error", buffer, 999, filePath);
      string result = Encoding.Default.GetString(buffer, 0, length);
      return result;
    }
    /// <summary>
    /// 获取ini文件中所有的section名称
    /// </summary>
    /// <param name="filePath">ini文件路径</param>
    /// <returns>返回一个包含section名称的string数组</returns>
    public static string[] GetSectionNames(string filePath) {
      byte[] buffer = new byte[2048];
      int length = GetPrivateProfileString(null, "", "", buffer, 999, filePath);
      string result = Encoding.Default.GetString(buffer, 0, length);
      return result.Split(new[] { "\0" }, StringSplitOptions.RemoveEmptyEntries);
    }
    /// <summary>
    /// 获取ini文件中指定区域的所有键的值
    /// </summary>
    /// <param name="sectionName">指定的区域</param>
    /// <param name="filePath">文件路径</param>
    /// <returns>指定区域下的所有键的值组成的string数组</returns>
    public static string[] GetKeys(string sectionName, string filePath) {
      byte[] buffer = new byte[2048];
      int length = GetPrivateProfileString(sectionName, null, "", buffer, 999, filePath);
      string result = Encoding.Default.GetString(buffer, 0, length);
      return result.Split(new[] { "\0" }, StringSplitOptions.RemoveEmptyEntries);
    }
    /// <summary>
    /// 获取指定区域(section)下的所有所有的键和值
    /// </summary>
    /// <param name="sectionName">section名</param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns></returns>
    public static List<(string, string)> GetKeyAndValues(string sectionName, string filePath) {
      List<(string, string)> list = new List<(string, string)>();
      string[] keys = GetKeys(sectionName, filePath);

      foreach(string key in keys) {
        string v = GetSpecifiedValue(sectionName, key, filePath);
        list.Add((key, v));
      }

      return list;
    }

    #endregion

    #region 写入INI文件
    /// <summary>
    /// 对INI文件进行写入操作
    /// </summary>
    /// <param name="sectionName">要写入的区域名称</param>
    /// <param name="key">要写入的键的名称，若为null，则将移除指定的区域(section)</param>
    /// <param name="value">设置key所对应的值，若为null，将移除指定的key</param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns></returns>
    [DllImport("kernel32")]
    private static extern long WritePrivateProfileString(string sectionName, string key, string value, string filePath);
    /// <summary>
    /// 对INI文件进行写入操作
    /// </summary>
    /// <param name="sectionName">要写入的区域名称</param>
    /// <param name="key">要写入的键的名称，若为null，则将移除指定的区域(section)</param>
    /// <param name="value">设置key所对应的值，若为null，将移除指定的key</param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns></returns>
    public static long Write(string sectionName, string key, string value, string filePath) {
      return WritePrivateProfileString(sectionName, key, value, filePath);
    }

    /// <summary>
    /// 保存内容到ini文件
    /// <para>若存在相同的key，就覆盖，否则就新增</para>
    /// </summary>
    /// <param name="sectionName">要写入的区域名称</param>
    /// <param name="key">要写入的键的名称，若为null，则将移除指定的区域(section)</param>
    /// <param name="value">设置key所对应的值，若为null，将移除指定的key</param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns></returns>
    public static bool SetValue(string sectionName, string key, string value, string filePath) {
      long result = WritePrivateProfileString(sectionName, key, value, filePath);
      return result > 0;
    }

    /// <summary>
    /// 移除指定的区域(section)
    /// </summary>
    /// <param name="sectionName">section名</param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns></returns>
    public static bool RemoveSpecifiedSection(string sectionName, string filePath) {
      long result = WritePrivateProfileString(sectionName, null, "", filePath);
      return result > 0;
    }
    /// <summary>
    /// 移除指定的key
    /// </summary>
    /// <param name="secionName">section名</param>
    /// <param name="key">键名</param>
    /// <param name="filePath">ini文件路径</param>
    /// <returns></returns>
    public static bool RemoveKey(string secionName, string key, string filePath) {
      long result = WritePrivateProfileString(secionName, key, null, filePath);
      return result > 0;
    }

    #endregion
  }
}
